package org.xiaoyu.rpc.remoting.codec;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.util.AttributeKey;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.xiaoyu.rpc.common.constant.RpcError;
import org.xiaoyu.rpc.common.exception.RpcException;
import org.xiaoyu.rpc.common.exception.SerializeException;
import org.xiaoyu.rpc.remoting.packet.*;
import org.xiaoyu.rpc.seralization.Serializer;
import org.xiaoyu.rpc.seralization.support.SerializerAlgorithm;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created By Have
 * 2021/7/5 13:37
 */
@Slf4j
@Deprecated
public class PacketCodeC {
    public static final int MAGIC_NUMBER = 0x12345678;
    private static volatile PacketCodeC singleton;
    public static final AttributeKey<byte[]> PACKET_CACHE_KEY = AttributeKey.newInstance("PACK_CACHE");


    private PacketCodeC() {

    }

    public static PacketCodeC getSingleton() {
        if (singleton == null) {
            synchronized (PacketCodeC.class) {
                if (singleton == null) {
                    singleton = new PacketCodeC();
                }
            }
        }
        return singleton;
    }

    public List<ByteBuf> encode(Channel channel, Packet packet, List<Object> out) {
        byte[] bytes = new byte[0];
        if (packet.getSerializerType() == SerializerAlgorithm.FASTJSON.getType()) {
            bytes = SerializerAlgorithm.FASTJSON.getSerializer().serializer(packet);
        } else if (packet.getSerializerType() == SerializerAlgorithm.KRYO.getType()) {
            bytes = SerializerAlgorithm.KRYO.getSerializer().serializer(packet);
        } else if (packet.getSerializerType() == SerializerAlgorithm.HESSIAN2.getType()) {
            bytes = SerializerAlgorithm.HESSIAN2.getSerializer().serializer(packet);
        } else if (packet.getSerializerType() == SerializerAlgorithm.PROTOBUF.getType()) {
            bytes = SerializerAlgorithm.PROTOBUF.getSerializer().serializer(packet);
        } else {
            log.error("不存在的序列化器");
            throw new SerializeException("序列化器不存在");
        }

        int begin = 0;
        int end = bytes.length;
        List<ByteBuf> byteBufs = new ArrayList<>();
//        System.out.println(begin + ":" + end);
        while (begin < end) {
            ByteBuf byteBuf = channel.alloc().directBuffer(1024);
            int offset = Math.min(begin + 1008, end);
            if (offset == end && offset == (begin + 1008)) {

            }
            byteBuf.writeInt(MAGIC_NUMBER);
            byteBuf.writeInt(packet.getType());
            byteBuf.writeInt(packet.getSerializerType());
            byteBuf.writeInt(offset - begin); // write length
            byteBuf.writeBytes(Arrays.copyOfRange(bytes, begin, offset));
            if (offset == end) {
                byteBuf.writeByte('\n');
            }
            //            channel.writeAndFlush(byteBuf);
            byteBuf.resetReaderIndex();
            byteBufs.add(byteBuf);
            begin = offset;
        }
//        StringBuilder sb = new StringBuilder();
//        for (ByteBuf byteBuf : byteBufs) {
//            byte[] bytes1 = new byte[byteBuf.readableBytes()];
//            byteBuf.readBytes(bytes1);
//            String s = bytesToHexString(bytes1);
//            sb.append(s);
//            byteBuf.resetReaderIndex();
//        }
//        System.out.println(sb);
        return byteBufs;
    }


    public static String bytesToHexString(byte[] src){
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    public Object decode(Channel channel, ByteBuf buf, List<Object> out) throws Exception {
        int magicNumber = buf.readInt();
        if (magicNumber != MAGIC_NUMBER) {
            log.error("无法识别的包协议:[{}]", magicNumber);
            throw new RpcException(RpcError.NOT_SUPPORTED_PROTOCOL);
        }

        int packetType = buf.readInt();
        Class<?> packageClass;
        if (packetType == PacketType.REQUEST_PACK) {
            packageClass = Invocation.class;
        } else if (packetType == PacketType.RESPONSE_PACK) {
            packageClass = AppResponse.class;
        } else if (packetType == PacketType.HEARTBEAT_REQ_PACK) {
            packageClass = HeartbeatRequest.class;
        } else {
            log.error("无法识别的包类型:[{}]", packetType);
            throw new RpcException(RpcError.NOT_SUPPORTED_PACKET);
        }
        int serializerType = buf.readInt();
        Serializer serializer;
        if (serializerType == SerializerAlgorithm.FASTJSON.getType()) {
            serializer = SerializerAlgorithm.FASTJSON.getSerializer();
        } else if (serializerType == SerializerAlgorithm.KRYO.getType())  {
            serializer = SerializerAlgorithm.KRYO.getSerializer();
        } else if (serializerType == SerializerAlgorithm.HESSIAN2.getType()) {
            serializer = SerializerAlgorithm.HESSIAN2.getSerializer();
        } else if (serializerType == SerializerAlgorithm.PROTOBUF.getType()) {
            serializer = SerializerAlgorithm.PROTOBUF.getSerializer();
        } else {
            log.error("无法识别的序列化器类型:[{}]", serializerType);
            throw new RpcException(RpcError.NOT_SUPPORTED_SERIALIZER);
        }

        int length = buf.readInt();
        byte[] bytes = new byte[length];
        buf.readBytes(bytes);
        if(buf.isReadable() && buf.readByte() == 10) { // 遇到断位符
            byte[] res = channel.attr(PACKET_CACHE_KEY).get();
            channel.attr(PACKET_CACHE_KEY).set(null);
            if (res!=null && res.length > 0) {
                byte[] newBytes = new byte[res.length + bytes.length];
                System.arraycopy(res, 0, newBytes, 0, res.length);
                System.arraycopy(bytes, 0, newBytes, res.length, bytes.length);
                bytes = newBytes;
            }
            Object packet = serializer.deserializer(packageClass, bytes);
            return packet;
        } else { // 受到的包不完整暂时缓存
            byte[] res = channel.attr(PACKET_CACHE_KEY).get();
            if (res != null && res.length > 0) {
                byte[] newBytes = new byte[res.length + bytes.length];
                System.arraycopy(res, 0, newBytes, 0, res.length);
                System.arraycopy(bytes, 0, newBytes, res.length, bytes.length);
                channel.attr(PACKET_CACHE_KEY).set(newBytes);
            } else {
                channel.attr(PACKET_CACHE_KEY).set(bytes);
            }
        }

        return null;
    }

    public static void main(String[] args) {
        byte[] bytes = "\n".getBytes(StandardCharsets.UTF_8);
        System.out.println(bytes.length);

        bytes = new byte[] {1,2,3};
        System.out.println(Arrays.toString(Arrays.copyOfRange(bytes, 0, 2)));
    }
}
